/**
 * Created by woziji00226 on 2025-01-07 14:16:28.
 */





class GUI_SegmentGame_W26 extends GUI_15001 {

    /**
     * 当前等级
     */
    private _currentLevel: number = 0;

    /**
     * 当前数据
     */
    private _currentData: SegmentData_W26

    /**
     * 步数
     */
    private _step: number = 0;

    /**
     * 分数
     */
    private _score: number = 0;

    /**
     * 抓取数据
     */
    private _dropData: {
        point: number,
        lastMousePoint: Point
    } = { point: null, lastMousePoint: new Point() };

    private _drawPointRadis: number = 15;
    private _drawPointBackRadis: number = 10;

    constructor() {
        super()
        this.level = 0;
        this.score = 0;
        this.step = 0;
        
        this._initMouse();
        this._startLevel(0);

        this.nextLevelButton.on(EventObject.CLICK, this, this._nextLevel);
        this.gameOverButton.on(EventObject.CLICK, this, this._restart);
        this.gameWinButton.on(EventObject.CLICK, this, this._restart);


        this.once(GameSprite.ON_DISPOSE, this, () => {
            this.nextLevelButton.offAll();
            this.gameOverButton.offAll();
            this.gameWinButton.offAll();
        })

    }

    private _initMouse() {
        stage.on(EventObject.MOUSE_DOWN, this, this._onMouseDown);
        stage.on(EventObject.MOUSE_MOVE, this, this._onMouseMove);
        stage.on(EventObject.MOUSE_UP, this, this._onMouseUp);


        this.once(GameSprite.ON_DISPOSE, this, () => {
            stage.off(EventObject.MOUSE_DOWN, this, this._onMouseDown);
            stage.off(EventObject.MOUSE_MOVE, this, this._onMouseMove);
            stage.off(EventObject.MOUSE_UP, this, this._onMouseUp);
        })

    }

    private _onMouseDown(e: EventObject) {
        if (!this.visible) {
            return;
        }


        if (this._dropData.point != null || this._currentData == null) {
            return;
        }

        var radis = this._drawPointRadis + this._drawPointBackRadis;

        var points = this._currentData.points;

        //debugger;

        for (var i = 0; i < points.length; i++) {
            var point = points[i];
            var result = this._collisionCircle(this.visibleContainer.mouseX, this.visibleContainer.mouseY, point.x, point.y, radis);
            if (result) {
                this._dropData.lastMousePoint.x = this.visibleContainer.mouseX;
                this._dropData.lastMousePoint.y = this.visibleContainer.mouseY;
                this._dropData.point = i;
                break;
            }
        }
    }

    private _onMouseMove(e: EventObject) {
        if (!this.visible) {
            return;
        }

        if (this._dropData.point == null || this._currentData == null) {
            return;
        }

        var currentMouseX = this.visibleContainer.mouseX;
        var currentMouseY = this.visibleContainer.mouseY;
        var lastMouseX = this._dropData.lastMousePoint.x;
        var lastMouseY = this._dropData.lastMousePoint.y;

        var xi = currentMouseX - lastMouseX;
        var yi = currentMouseY - lastMouseY;


        this._currentData.points[this._dropData.point].x += xi;
        this._currentData.points[this._dropData.point].y += yi;

        this._dropData.lastMousePoint.x = currentMouseX;
        this._dropData.lastMousePoint.y = currentMouseY;
        this._draw();


    }

    private _onMouseUp() {
        if (!this.visible) {
            return;
        }


        if (this._dropData.point == null || this._currentData == null) {
            return;
        }

        this._dropData.point = null;

        this._refresh();
        this._draw();

        this._checkGameStatus();
    }




    /**
     * 开始一个新等级
     * @param level 
     */
    private _startLevel(level: number = null) {

        this.nextLevelUI.visible = false;
        this.gameOverUI.visible = false;
        this.gameWinUI.visible = false;

        this.level = level || this.level + 1;
        this.level = Math.max(1, Math.min(SegmentGameData_W26.GameData.maxLevel, this.level));
        this.step = Math.round(.5 * this.level * (Math.ceil(this.level / 10) + 1));

        this._currentData = SegmentGameData_W26.GameData.getLevelData(this.level);

        this._refresh();
        this._draw();
    }

    private _restart() {
        this.level = 0;
        this.score = 0;
        this.step = 0;
        this._startLevel();
    }

    /**
     * 游戏结束
     */
    private _gameOver() {
        this.gameOverUI.visible = true;
    }

    /**
     * 下一关
     */
    private _nextLevel() {
        this._startLevel();
    }

    /**
     * 游戏胜利
     */
    private _gameWin() {
        this.gameWinUI.visible = true;
    }

    /**
     * 检查游戏状态
     */
    private _checkGameStatus() {
        var points = this._currentData.points;
        var result = true;
        for (var i = 0; i < points.length; i++) {
            var point = points[i];
            if (point.count != 0) {
                result = false;
                break;
            }
        }

        if (!result) {
            this.step -= 1;
            if (this.step == 0) {
                this._gameOver();
            }
        }
        else if (this.level + 1 > SegmentGameData_W26.GameData.maxLevel) {
            this.score += this.step;
            this._gameWin();
        }
        else {
            this.score += this.step;
            this.nextLevelUI.visible = true;
        }

    }

    /**
     * 圆碰撞检测，主要检测鼠标是不是点在圆里，用于移动点
     * @param px 点x
     * @param py 点y
     * @param cx 圆心x
     * @param cy 圆心y
     * @param radius 圆半径
     * reuturn 检查结果
     */
    private _collisionCircle(px: number, py: number, cx: number, cy: number, radius: number): boolean {
        //欧几里得距离公式  
        var distance = Math.sqrt(Math.pow((px - cx), 2) + Math.pow((py - cy), 2));
        if (radius > distance) {
            return true;
        }
        return false;
    }


    /**
     * 计算叉积结果
     * @return [number] 
     */
    private _orientation(p: [number, number], q: [number, number], r: [number, number]): number {
        // 计算 (q - p) × (r - p)
        const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);

        if (val === 0) return 0; // 共线
        return val > 0 ? 1 : 2; // 顺时针或逆时针
    }

    /**
     * 检查 q 是否在 p 和 r 的矩形范围内（用于判断是否在线段上，因为共线的情况下，在矩形范围内，就只能在线上了）
     * @return [boolean] 
     */
    private _onSegment(p: [number, number], q: [number, number], r: [number, number]): boolean {
        // 检查 q 是否在 p 和 r 的矩形范围内
        return (
            q[0] <= Math.max(p[0], r[0]) &&
            q[0] >= Math.min(p[0], r[0]) &&
            q[1] <= Math.max(p[1], r[1]) &&
            q[1] >= Math.min(p[1], r[1])
        );
    }

    /**
     * 检查线段是否相交
     * 
     * 采用的是向量的叉积法
     * 叉积的结果为平行四边形面积
     * 正负号则取决于从 向量 o1 到向量 o2 的旋转方向：如果按照右手规则，逆时针旋转，则结果为正；如果是顺时针旋转，则结果为负；如果两向量共线，则结果为零
     * 
     * 现在就取 a里的p1点和p2点 到 b的p1点 p2点 与 b的叉积，如果它们是一正一负，说明a的p1点p2点在b的两侧。
     * 然后对b的p1点和p2点到a也做同样的检测，结果也是一正一负，说明b的p1点和p2点在a的两侧。此时它们相交。
     * 
     * @param x1 
     * @param y1 
     * @param x2 
     * @param y2 
     * @param x1 
     * @param y1 
     * @param x2 
     * @param y2 
     * @return [boolean] 
     */
    private _collisionSegmentsIntersect(a: { x1: number, y1: number, x2: number, y2: number }, b: { x1: number, y1: number, x2: number, y2: number }): boolean {
        // 定义点
        const p1: [number, number] = [a.x1, a.y1];
        const q1: [number, number] = [a.x2, a.y2];
        const p2: [number, number] = [b.x1, b.y1];
        const q2: [number, number] = [b.x2, b.y2];

        // 四个方向：p1q1 到 q2 的方向，p1q1 到 p2 的方向，p2q2 到 p1 的方向，p2q2 到 q1 的方向
        const o1 = this._orientation(p1, q1, p2);
        const o2 = this._orientation(p1, q1, q2);
        const o3 = this._orientation(p2, q2, p1);
        const o4 = this._orientation(p2, q2, q1);

        // 一般情况
        if (o1 !== o2 && o3 !== o4) return true;
        //debugger;
        // 特殊情况
        // p1, q1 和 p2 共线且 p2 在 p1q1 上
        if (o1 === 0 && this._onSegment(p1, p2, q1)) return true;
        // p1, q1 和 q2 共线且 q2 在 p1q1 上
        if (o2 === 0 && this._onSegment(p1, q2, q1)) return true;
        // p2, q2 和 p1 共线且 p1 在 p2q2 上
        if (o3 === 0 && this._onSegment(p2, p1, q2)) return true;
        // p2, q2 和 q1 共线且 q1 在 p2q2 上
        if (o4 === 0 && this._onSegment(p2, q1, q2)) return true;

        return false; // 不相交
    }


    /**
     * 更新
     */
    private _refresh(isMoving: boolean = false) {

        var currentData = this._currentData;

        //检查碰撞，对每个点检查 它的连线和其他线段是否发生碰撞 发生碰撞几次
        //无碰撞   绘制绿色的内圆 蓝色外圆 连线是绿色的
        //一次碰撞 绘制黄色的内圆 蓝色外圆 连线是黄色的
        //多次碰撞 绘制红色的内圆 蓝色外圆 连线是红色的

        for (var i = 0; i < currentData.points.length; i++) {
            currentData.points[i].count = 0;
        }

        for (var i = 0; i < currentData.segments.length; i++) {
            currentData.segments[i].count = 0;
        }

        for (var i = 0; i < currentData.segments.length; i++) {
            var segment = currentData.segments[i];
            var p1 = segment.p1;
            var p2 = segment.p2;

            var point1 = currentData.points[p1];
            var point2 = currentData.points[p2];

            //从后一个开始
            for (var j = i + 1; j < currentData.segments.length; j++) {
                var segmentTarget = currentData.segments[j];
                var p1Target = segmentTarget.p1;
                var p2Target = segmentTarget.p2;

                var pointT1 = currentData.points[p1Target];
                var pointT2 = currentData.points[p2Target];

                //如果有一个点是端点，就不用判断。因为不将此情况算作相交
                if (p1 === p1Target || p1 === p2Target || p2 === p1Target || p2 === p2Target) {
                    continue;
                }

                var result = this._collisionSegmentsIntersect({
                    x1: point1.x,
                    y1: point1.y,
                    x2: point2.x,
                    y2: point2.y
                }, {
                    x1: pointT1.x,
                    y1: pointT1.y,
                    x2: pointT2.x,
                    y2: pointT2.y
                });


                if (result) {
                    //相交
                    currentData.points[p1].count += 1;
                    currentData.points[p2].count += 1;
                    currentData.points[p1Target].count += 1;
                    currentData.points[p2Target].count += 1;


                    currentData.segments[i].count += 1;
                    currentData.segments[j].count += 1;
                }
            }
        }
        this._draw();
    }


    private _draw() {
        var g = this.visibleContainer.graphics;
        g.clear();

        var currentData = this._currentData;

        for (var i = 0; i < currentData.segments.length; i++) {
            //debugger;
            var segment = currentData.segments[i];
            var p1 = currentData.points[segment.p1];
            var p2 = currentData.points[segment.p2];

            var color = "#00FF00";
            if (segment.count == 1) {
                color = "#FFFF00";
            }
            if (segment.count > 1) {
                color = "#FF0000";
            }

            g.drawLine(p1.x, p1.y, p2.x, p2.y, color, 2);

        }

        for (var i = 0; i < currentData.points.length; i++) {
            var point = currentData.points[i];
            var color = "#00FF00";
            if (point.count == 1) {
                color = "#FFFF00";
            }
            if (point.count > 1) {
                color = "#FF0000";
            }
            g.drawCircle(point.x, point.y, 15, color, "#0000FF", 10);

        }
    }


    private set level(value: number) {
        this._currentLevel = value;
        this.nextLevelLabel.text = `第${this._currentLevel}关，恭喜闯关成功`;
        this.gameOverLabel.text = `第${this._currentLevel}关，闯关失败`;
        this.gameWInLabel.text = `第${this._currentLevel}关，游戏胜利！`;
    }

    private get level() {
        return this._currentLevel;
    }


    private set step(value: number) {
        this._step = value;
        this.stepLabel.text = `剩余步数:${this._step.toString()}`;
    }


    private get step() {
        return this._step;
    }

    private set score(value: number) {
        this._score = value;
        this.nextLevelScoreLabel.text = `分数：${this._score.toString()}`;
        this.gameOverScoreLabel.text = `分数：${this._score.toString()}`;
        this.gameWinScoreLabel.text = `分数：${this._score.toString()}`;
    }

    private get score() {
        return this._score;
    }



}